package com.maiikun.thread_pool;

import com.maiikun.thread_pool.reject.RejectHandle;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class MyThreadPool {

    public MyThreadPool(int coreSize, int maxSize, int waitTime, TimeUnit timeUnit, LinkedBlockingQueue<Runnable> commandList,
                        RejectHandle rejectHandle) {
        if (maxSize < coreSize) throw new RuntimeException("最大线程不可小于核心线程");
        this.coreSize = coreSize;
        this.maxSize = maxSize;
        this.waitTime = waitTime;
        this.timeUnit = timeUnit;
        this.commandList = commandList;
        this.rejectHandle = rejectHandle;
        threadFactory = Executors.defaultThreadFactory();
    }

    public MyThreadPool(int coreSize, int maxSize, int waitTime, TimeUnit timeUnit, LinkedBlockingQueue<Runnable> commandList,
                        RejectHandle rejectHandle, ThreadFactory threadFactory) {
        if (maxSize < coreSize) throw new RuntimeException("最大线程不可小于核心线程");
        this.coreSize = coreSize;
        this.maxSize = maxSize;
        this.waitTime = waitTime;
        this.timeUnit = timeUnit;
        this.commandList = commandList;
        this.rejectHandle = rejectHandle;
    }

    private int coreSize;
    private int maxSize;
    private int waitTime;
    private TimeUnit timeUnit;
    private RejectHandle rejectHandle;
    private ThreadFactory threadFactory;

    // 工作队列 - 阻塞队列
    public BlockingQueue<Runnable> commandList;
    // 核心队列
    List<Thread> coreThreadList = new ArrayList<>(coreSize);
    // 辅助线程队列
    List<Thread> supportThreadList = new ArrayList<>(maxSize - coreSize);

    public void execute(Runnable command) {
        // 核心线程未满的时候 来一个任务就新建一个线程
        synchronized (this) {
            if (coreThreadList.size() < coreSize) {
                Thread thread = threadFactory.newThread(coreRunnable);
//                        new coreThread();
                thread.start();
                coreThreadList.add(thread);
            }
        }

        synchronized (this) {
            // 阻塞队列是否添加成功
            if (!commandList.offer(command)) {
                // 添加失败
                // 添加到辅助队列中进行执行
                if (supportThreadList.size() + coreSize < maxSize) {
                    Thread thread = threadFactory.newThread(supportRunnable);
//                            new SupportThread();
                    thread.start();
                    supportThreadList.add(thread);
                }
                // 辅助队列也加满了
                if (!commandList.offer(command)) {
                    // 执行拒绝策略 怎么处理多余的任务? - RejectHandle
                    rejectHandle.reject(command, this);
                    System.out.println("阻塞队列满了");
                }
            }
        }
    }


    Runnable coreRunnable = () -> {
        while (true) {
            try {
                Runnable runnable = commandList.take();
                runnable.run();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    };


    Runnable supportRunnable = () -> {
        while (true) {
            try {
                Runnable runnable = commandList.poll(waitTime, timeUnit);
                if (runnable == null) {
                    // 指定时间内没有拿到任务
                    break;
                }
                runnable.run();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        System.out.println(Thread.currentThread().getName() + "辅助线程结束了");
    };



    // 核心线程的执行逻辑
    class coreThread extends Thread {
        @Override
        public void run() {
            while (true) {
                try {
                    Runnable runnable = commandList.take();
                    runnable.run();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    // 辅助线程执行逻辑 若超过一定时间没有拿到任务则自动销毁
    // 核心线程的执行逻辑
    class SupportThread extends Thread {
        @Override
        public void run() {
            while (true) {
                try {
                    Runnable runnable = commandList.poll(waitTime, timeUnit);
                    if (runnable == null) {
                        // 指定时间内没有拿到任务
                        break;
                    }
                    runnable.run();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println(Thread.currentThread().getName() + "辅助线程结束了");
        }
    }

}
